//
//  CoreData.m
//  MoneyIndividual
//
//  Created by Le Anh Tai on 1/6/14.
//  Copyright (c) 2014 Le Anh Tai. All rights reserved.
//

#import "CoreData.h"
#import "RootViewController.h"

@implementation CoreData

@synthesize managedObjectContext = _managedObjectContext;
@synthesize managedObjectModel = _managedObjectModel;
@synthesize persistentStoreCoordinator = _persistentStoreCoordinator;

static CoreData *_shared;

+ (CoreData *)shared
{
    if (_shared == nil)
    {
        _shared = [[CoreData alloc] init];
    }
    
    return _shared;
}

- (id)init
{
    if (self = [super init])
    {
        
    }
    
    return self;
}

- (BOOL)saveContext
{
    NSError *error = nil;
    NSManagedObjectContext *managedObjectContext = self.managedObjectContext;
    if (managedObjectContext != nil) {
        if ([managedObjectContext hasChanges] && ![managedObjectContext save:&error]) {
            // Replace this implementation with code to handle the error appropriately.
            // abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
            NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
            abort();
            return NO;
        }
    }
    
    return YES;
}

#pragma mark - Import data

#pragma mark - popular Methods
- (NSManagedObject *)newEntity:(NSString *)entityName
{
    NSManagedObject *object = [NSEntityDescription
                               insertNewObjectForEntityForName:entityName
                               inManagedObjectContext:self.managedObjectContext];
        
    return object;
}

- (NSArray *)fetchEntity:(NSString *)entityName
{
    return [self fetchEntity:entityName withPredicate:nil sortAttribute:nil isAscending:NO];
}

- (NSArray*)fetchEntity:(NSString*)entityName withPredicates:(NSArray*)predicates sortAttribute:(NSString*)attribute isAscending:(BOOL)isAscending
{
    NSManagedObjectContext *moc = [self managedObjectContext];
    NSEntityDescription *entityDescription = [NSEntityDescription
                                              entityForName:entityName inManagedObjectContext:moc];
    NSFetchRequest *request = [[NSFetchRequest alloc] init];
    [request setEntity:entityDescription];
    
    // Set example predicate and sort orderings...
    if (predicates)
    {
        NSPredicate *compoundpred = [NSCompoundPredicate andPredicateWithSubpredicates:predicates];
        [request setPredicate:compoundpred];
    }
    
    if (attribute)
    {
        NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc]
                                            initWithKey:attribute ascending:isAscending];
        [request setSortDescriptors:@[sortDescriptor]];
    }
    
    NSError *error;
    NSArray *array = [moc executeFetchRequest:request error:&error];
    if (array == nil)
    {
        // Deal with error...
    }
    
    return array;
}

- (NSArray*)fetchEntity:(NSString*)entityName withPredicate:(NSPredicate *)predicate sortAttribute:(NSString*)attribute isAscending:(BOOL)isAscending
{
    if (predicate)
    {
        return [self fetchEntity:entityName withPredicates:@[predicate] sortAttribute:attribute isAscending:isAscending];
    }
    
    return [self fetchEntity:entityName withPredicates:nil sortAttribute:attribute isAscending:isAscending];
}

- (NSFetchedResultsController *)fetchedResultsControllerWithEntity:(NSString *)entityName
                                                      sortProperty:(NSString *)sortProperty
                                                       isAscending:(BOOL)isAscending
                                                           groupBy:(NSString *)groupByProperty
                                                         cacheName:(NSString *)cacheName
{
    return [self fetchedResultsControllerWithEntity:entityName predicates:nil sortProperty:sortProperty isAscending:isAscending groupBy:groupByProperty cacheName:cacheName];
}

- (NSFetchedResultsController *)fetchedResultsControllerWithEntity:(NSString *)entityName
                                                        predicates:(NSArray *)predicates
                                                      sortProperty:(NSString *)sortProperty
                                                       isAscending:(BOOL)isAscending
                                                           groupBy:(NSString *)groupByProperty
                                                         cacheName:(NSString *)cacheName
{
    return [self fetchedResultsControllerWithEntity:entityName andPredicates:predicates orPredicates:nil sortProperties:@[sortProperty] isAscending:isAscending groupBy:groupByProperty cacheName:cacheName];
}

- (NSFetchedResultsController *)fetchedResultsControllerWithEntity:(NSString *)entityName
                                                        andPredicates:(NSArray *)andPredicates
                                                     orPredicates:(NSArray *)orPredicates
                                                      sortProperties:(NSArray *)sortProperties
                                                       isAscending:(BOOL)isAscending
                                                           groupBy:(NSString *)groupByProperty
                                                         cacheName:(NSString *)cacheName
{
    NSManagedObjectContext *moc = [self managedObjectContext];
    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
    NSEntityDescription *entity = [NSEntityDescription
                                   entityForName:entityName inManagedObjectContext:moc];
    [fetchRequest setEntity:entity];
    
    NSPredicate *andPredicate = nil;
    if (andPredicates && andPredicates.count > 0)
    {
        andPredicate = [NSCompoundPredicate andPredicateWithSubpredicates:andPredicates];
    }
    
    NSPredicate *orPredicate = nil;
    if (orPredicates && orPredicates.count > 0)
    {
        orPredicate = [NSCompoundPredicate orPredicateWithSubpredicates:orPredicates];
    }
    
    if (andPredicate && orPredicate)
    {
        NSPredicate *compound = [NSCompoundPredicate andPredicateWithSubpredicates:@[andPredicate, orPredicate]];
        [fetchRequest setPredicate:compound];
    }
    else if (andPredicate)
    {
        [fetchRequest setPredicate:andPredicate];
    }
    else if (orPredicate)
    {
        [fetchRequest setPredicate:orPredicate];
    }
    
    //must have at leat one sort
    NSMutableArray *sorts = [[NSMutableArray alloc] init];
    for (NSString *sortProperty in sortProperties)
    {
        NSSortDescriptor *sort = [[NSSortDescriptor alloc]
                                  initWithKey:sortProperty ascending:isAscending];
        [sorts addObject:sort];
    }
    
    [fetchRequest setSortDescriptors:sorts];
    
    //number of row will be fetched and automatically fetch more when scrolling tableview
    [fetchRequest setFetchBatchSize:20];
    
    NSFetchedResultsController *theFetchedResultsController =
    [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest
                                        managedObjectContext:moc
                                          sectionNameKeyPath:groupByProperty//indicate the property name to group by
                                                   cacheName:cacheName];
    return theFetchedResultsController;
}

- (BOOL)deleteObject:(NSManagedObject *)object
{
    if (object == nil && [object isKindOfClass:[NSManagedObject class]] == NO)
    {
        return NO;
    }
    
    [_managedObjectContext deleteObject:object];
    
    [[CoreData shared] saveContext];
    
    return YES;
}

#pragma mark - Core Data stack
// Returns the managed object context for the application.
// If the context doesn't already exist, it is created and bound to the persistent store coordinator for the application.
- (NSManagedObjectContext *)managedObjectContext
{
    if (_managedObjectContext != nil)
    {
        return _managedObjectContext;
    }
    
    NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
    if (coordinator != nil)
    {
//        _managedObjectContext = [[NSManagedObjectContext alloc] init];
        _managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
        [_managedObjectContext setPersistentStoreCoordinator:coordinator];
    }
    return _managedObjectContext;
}

// Returns the managed object model for the application.
// If the model doesn't already exist, it is created from the application's model.
- (NSManagedObjectModel *)managedObjectModel
{
    if (_managedObjectModel != nil) {
        return _managedObjectModel;
    }
    NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"database" withExtension:@"momd"];
    _managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
    return _managedObjectModel;
}

// Returns the persistent store coordinator for the application.
// If the coordinator doesn't already exist, it is created and the application's store added to it.
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator
{
    if (_persistentStoreCoordinator != nil) {
        return _persistentStoreCoordinator;
    }
    
    NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"database.sqlite"];
    
    NSError *error = nil;
    _persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
    
    NSDictionary *options = @{
                              NSMigratePersistentStoresAutomaticallyOption : @YES,
                              NSInferMappingModelAutomaticallyOption : @YES,
                              NSSQLitePragmasOption:@{@"journal_mode":@"DELETE"}
                              };
    
    if (! [_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType
                                                   configuration:nil
                                                             URL:storeURL
                                                         options:options
                                                           error:&error]) {
        // error handling.
        NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
    }
    
    return _persistentStoreCoordinator;
}

#pragma mark - Application's Documents directory

// Returns the URL to the application's Documents directory.
- (NSURL *)applicationDocumentsDirectory
{
    return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
}


@end
